#!/usr/bin/env python
# encoding: utf-8

"""
@time: 2016/12/6 下午5:20
"""
# 三角形的常用的工具
from sympy import solveset, symbols, tan
from itertools import permutations
from mathsolver.functions.base import *
from mathsolver.functions.budengshi import common_opers as co
from mathsolver.functions.sanjiao import sanjiao_utils as su
from mathsolver.functions.sanjiao.triangle_constant import BASE_LINE_SUBS, TRIANGLE_NAME_SEARCH_KEY, TRIANGLE_KNOWN_KEY
from itertools import chain


def is_in_triangle(know):
    """
    是否在三角形中
    :param know: 
    :return: 
    """
    return TRIANGLE_NAME_SEARCH_KEY in know


def legal_sided(side_v):
    """
    是否是合法的边
    :param side_v:
    :return:
    """
    side_v = sympify(side_v)
    if not side_v.is_real:
        return False
    base_intl = Interval(0, S.Infinity, left_open=True)
    s_intl = solveset(str(side_v) + '>0', domain=S.Reals)
    last_intl = base_intl.intersect(s_intl)
    return last_intl


def legal_sides(side_values):
    """
    是否是合法的三边的值. 是否满足两边之和大于第三边。
    ((a, c/2), (b /c/4), (c, c))
    :param side_values:
    :return:
    """
    pers = permutations(side_values, 3)
    for per in pers:
        f_v, s_v, t_v = per
        if not solveset(str(f_v + s_v - t_v) + '>0', domain=S.Reals).intersect(
                Interval(0, S.Infinity, left_open=True)):
            return False
    return True


def acute_triangled(side_values):
    """
    是否是锐角三角形
    :param side_values: 三边的值
    :return:
    """
    line1, line2, line3 = side_values
    angle1_cos = (line2 ** 2 + line3 ** 2 - line1 ** 2) / (2 * line2 * line3)
    angle2_cos = (line1 ** 2 + line3 ** 2 - line2 ** 2) / (2 * line1 * line3)
    angle3_cos = (line1 ** 2 + line2 ** 2 - line3 ** 2) / (2 * line1 * line2)
    if angle1_cos > 0 and angle2_cos > 0 and angle3_cos > 0:
        return True
    else:
        return False


def obtuse_triangled(side_values):
    """
    是否是钝角三角形
    :param side_values: 三边的值
    :return:
    """
    line1, line2, line3 = side_values
    angle1_cos = (line2 ** 2 + line3 ** 2 - line1 ** 2) / (2 * line2 * line3)
    angle2_cos = (line1 ** 2 + line3 ** 2 - line2 ** 2) / (2 * line1 * line3)
    angle3_cos = (line1 ** 2 + line2 ** 2 - line3 ** 2) / (2 * line1 * line2)
    if angle1_cos < 0 or angle2_cos < 0 or angle3_cos < 0:
        return True
    else:
        return False


def triangle_area(side_values):
    """
    求三角形的面积
    :param side_values: 三边的值
    :return:
    """
    a_v, b_v, c_v = side_values
    p = sympify('p')
    area = sympify('sqrt(p*(p-a)*(p-b)*(p-c))')
    area = simplify(area.subs(p, '(a+b+c)/2').subs((('a', a_v), ('b', b_v), ('c', c_v))))
    return area


def triangle_angle_cos(side_values, angle):
    """
    计算三角形的角的cos值
    :param side_values: 三边的值
    :param angle: 角的值
    :return:
    """
    angle_side = sympify(str(angle).lower())
    sides = FiniteSet(*map(lambda sv: sympify(sv[0]), side_values))
    side1, side2 = sides - FiniteSet(angle_side)
    cos_v = (side1 ** 2 + side2 ** 2 - angle_side ** 2) / (2 * side1 * side2)
    return simplify(cos_v.subs(side_values))


def triangle_line_subs(f):
    """
    替换三边都为a,b,c
    :param f:
    :return:
    """
    line_subs = (('line(AB)', 'c'), ('line(AC)', 'b'), ('line(BC)', 'a'),
                 ('line(BA)', 'c'), ('line(CA)', 'b'), ('line(CB)', 'a'),
                 ('line(A, B)', 'c'), ('line(A, C)', 'b'), ('line(B, C)', 'a'),
                 ('line(B, A)', 'c'), ('line(C, A)', 'b'), ('line(C, B)', 'a'),
                 ('baseLine(AB)', 'c'), ('baseLine(AC)', 'b'), ('baseLine(BC)', 'a'),
                 ('baseLine(BA)', 'c'), ('baseLine(CA)', 'b'), ('baseLine(CB)', 'a'),
                 ('AB', 'c'), ('AC', 'b'), ('BC', 'a'),
                 ('BA', 'c'), ('CA', 'b'), ('CB', 'a'))
    return f.subs(line_subs)


def triangle_angle_subs(f):
    """
    替换三角都为A, B, C
    :param f:
    :return:
    """
    angle_subs = (('Angle(A)', 'A'), ('Angle(B)', 'B'), ('Angle(C)', 'C'))
    return f.subs(angle_subs)


def triangle_default_subs(f):
    return triangle_angle_subs(triangle_line_subs(f))


def tan_subs(f):
    return f.subs(tan('A'), 'sin(A)/cos(A)').subs(tan('B'), 'sin(B)/cos(B)').subs(tan('C'), 'sin(C)/cos(C)')


LINE_SUBS = (('line(AB)', 'c'), ('line(AC)', 'b'), ('line(BC)', 'a'))


def process_triangle_expr(expr):
    """
    处理三角函数的表达式
    :param expr:
    :return:
    """
    expr = sympify(expr)
    return su.radianed(expr.subs(LINE_SUBS))


def process_cond_eq(eq):
    """
    预处理三角形中的等式条件
    :param eq: 等式
    :return:
    """
    eq_l, eq_r = eq.sympify()
    eq_l = eq_l.subs(LINE_SUBS)
    eq_l = su.radianed(eq_l)
    eq_r = eq_r.subs(LINE_SUBS)
    eq_r = su.radianed(eq_r)
    return BaseEq([eq_l, eq_r])


def preprocess_base_triangle_expr(triangle_expr):
    """
    预处理三角形中的表达式 比如 Line((A, B)) Line((A, C))
    :param triangle_expr: 
    :return: 
    >>> preprocess_base_triangle_expr('baseLine((A,C))')
    b
    """
    triangle_expr = sympify(triangle_expr)
    triangle_expr = triangle_angle_subs(triangle_expr)
    triangle_expr = triangle_line_subs(triangle_expr)
    triangle_expr = triangle_expr.subs(BASE_LINE_SUBS)
    return triangle_expr


def line_expr_subs(line_expr):
    """
    替换掉表达式中出现 line(A, B) 或者 line(AB)之类的情况
    :param line_expr: 
    :return: 
    >>> line_expr_subs('line(BA) + line(A, C)')
    AC + BA
    """
    line_expr = sympify(line_expr)
    lines = co.find_reg_expr(r'line\(.*?\)', str(line_expr))
    for line in lines:
        line = sympify(line)
        new_line = ''.join(sorted(map(str, line.free_symbols)))
        line_expr = line_expr.subs(line, new_line)
    return line_expr


def cos_law(adj_edge1, adj_edge2, opo_edge):
    """
    余弦定理
    :param adj_edge1: 角的临边1
    :param adj_edge2: 角的临边1
    :param opo_edge: 角的对边3
    :return: 
    """
    adj_edge1 = sympify(adj_edge1)
    adj_edge2 = sympify(adj_edge2)
    opo_edge = sympify(opo_edge)
    return (adj_edge1 ** 2 + adj_edge2 ** 2 - opo_edge ** 2) / (2 * adj_edge1 * adj_edge2)


def known_triangle_eqs(known):
    """
    从三角形中搜出关于三角的等式
    :param known:
    :return:
    """
    if not known:
        return None
    # try:
    #     known = known[TRIANGLE_KNOWN_KEY]
    # except:
    #     pass
    all_known = {}
    tmp_known = {k: v for k, v in known.items()}
    if TRIANGLE_KNOWN_KEY in tmp_known:
        known1 = tmp_known[TRIANGLE_KNOWN_KEY]
        all_known.update(known1)
        del tmp_known[TRIANGLE_KNOWN_KEY]
    all_known.update(tmp_known)
    known = dict(filter(lambda _: _[0] or _[1], all_known.items()))
    if not known:
        return None
    # eqs = map(lambda kv: (kv[0], list(kv[1])[0] if co.iterable(kv[1]) else kv[1]), known.items())
    eqs = []
    for k, v in known.items():
        ll = k
        try:
            r = list(co.flatten([v]))[0]
            eqs.append((ll, r))
        except Exception:
            pass
    arg_eqs = []
    for l_expr, r_expr in eqs:
        try:
            f = sympify(l_expr) - sympify(r_expr)
            f = preprocess_base_triangle_expr(f)
            if su.i_is_subset(f.free_symbols, symbols('A, B, C, a, b, c, ABC, ACB, BAC')):
                arg_eqs.append([f, '0'])
        except Exception:
            pass
    if arg_eqs:
        return BaseEqs(arg_eqs)
    else:
        return None


def simp_solve_triangle(eqs):
    """
    简单的解三角形
    :param eqs: 
    :return: 
    """
    from mathsolver.functions.sanjiao.triangle_cond_action_funcs import _two_cond_action_5
    if co.iterable(eqs):
        _result = _two_cond_action_5(BaseEqs(eqs))
    else:
        _result = _two_cond_action_5(eqs)
    return _result


def get_triangle_line_subs():
    line_subs = (('line(AB)', 'c'), ('line(AC)', 'b'), ('line(BC)', 'a'),
                 ('line(BA)', 'c'), ('line(CA)', 'b'), ('line(CB)', 'a'),
                 ('line(A, B)', 'c'), ('line(A, C)', 'b'), ('line(B, C)', 'a'),
                 ('line(B, A)', 'c'), ('line(C, A)', 'b'), ('line(C, B)', 'a'),
                 ('BaseLine(A, B)', 'c'), ('BaseLine(A, C)', 'b'), ('BaseLine(B, C)', 'a'),
                 ('BaseLine(B, A)', 'c'), ('BaseLine(C, A)', 'b'), ('BaseLine(C, B)', 'a'),
                 ('BaseLine(AB)', 'c'), ('BaseLine(AC)', 'b'), ('BaseLine(BC)', 'a'),
                 ('BaseLine(BA)', 'c'), ('BaseLine(CA)', 'b'), ('BaseLine(CB)', 'a'),
                 ('AB', 'c'), ('AC', 'b'), ('BC', 'a'),
                 ('BA', 'c'), ('CA', 'b'), ('CB', 'a'))
    return line_subs


def get_triangle_angle_subs():
    angle_subs = (('Angle(A)', 'A'), ('Angle(B)', 'B'), ('Angle(C)', 'C'),
                  ('Angle(B, A, C)', 'A'), ('Angle(A, B, C)', 'B'), ('Angle(A, C, B)', 'C'),
                  ('Angle(C, A, B)', 'A'), ('Angle(C, B, A)', 'B'), ('Angle(B, C, A)', 'C'),
                  ('BAC', 'A'), ('ABC', 'B'), ('ACB', 'C'), ('CAB', 'A'), ('CBA', 'B'), ('BCA', 'C'),
                  ('A', 'BAC'), ('B', 'ABC'), ('C', 'ACB'), ('A', 'CAB'), ('B', 'CBA'), ('C', 'BCA'))
    return angle_subs


def get_triangle_subs():
    """
    三角形中所有可能出现的形式 进行标准替换
    :return: 
    """
    line_subs = get_triangle_line_subs()
    line_subs = list(map(lambda _: (sympify(_[0]), sympify(_[1])), line_subs))
    angle_subs = get_triangle_angle_subs()
    angle_subs = list(map(lambda _: (sympify(_[0]), sympify(_[1])), angle_subs))
    return list(chain(line_subs, angle_subs))


def subs_triangle_expr(expr):
    """
    替换掉原始的baseLine((A, C))的东西
    :param expr: 
    :return: 
    """
    line_pattern1 = r'Line\(.*?\)'
    line_pattern2 = r'BaseLine\(.*?\)'
    lines1 = co.find_reg_expr(line_pattern1, str(expr))
    lines2 = co.find_reg_expr(line_pattern2, str(expr))
    lines = chain(lines1, lines2)
    _expr = sympify(expr)
    sympy_line_pattern1 = r'Line\((.*)\)'
    sympy_line_pattern2 = r'BaseLine\((.*)\)'
    for line in lines:
        m1 = re.search(sympy_line_pattern1, str(line))
        m2 = re.search(sympy_line_pattern2, str(line))
        if m1:
            points = m1.groups()[0].split(',')
        elif m2:
            points = m2.groups()[0].split(',')
        else:
            continue
        new_line = sympify(''.join(map(str.strip, points)))
        _expr = _expr.subs(line, new_line)
    return _expr


if __name__ == '__main__':
    pass
